﻿#region Copyright(c) Anton Shelin, Vladimir Timashkov. All Rights Reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2010 Anton Shelin, Vladimir Timashkov. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1. No Trademark License - Microsoft Public License (Ms-PL) does not grant you rights to use
//      authors names, logos, or trademarks.
//   2. If you distribute any portion of the software, you must retain all copyright,
//      patent, trademark, and attribution notices that are present in the software.
//   3. If you distribute any portion of the software in source code form, you may do
//      so only under this license by including a complete copy of Microsoft Public License (Ms-PL)
//      with your distribution. If you distribute any portion of the software in compiled
//      or object code form, you may only do so under a license that complies with
//      Microsoft Public License (Ms-PL).
//   4. The names of the authors may not be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// The software is licensed "as-is." You bear the risk of using it. The authors
// give no express warranties, guarantees or conditions. You may have additional consumer
// rights under your local laws which this license cannot change. To the extent permitted
// under your local laws, the authors exclude the implied warranties of merchantability,
// fitness for a particular purpose and non-infringement.
// -----------------------------------------------------------------------------
#endregion

using System;
using System.Web.Mvc;

namespace SharpDom.Mvc
{
    public class SharpDomViewEngine : IViewEngine
    {
        private readonly Func<ControllerContext, string, string, Type> _findTypeByControllerContextViewNameAndMasterName;

        /// <summary>Default constructor. View engine created by this constructor will search views 
        /// in current assembly and by type name root_namespace\views\controllername\actionname</summary>
        public SharpDomViewEngine()
        {
            _findTypeByControllerContextViewNameAndMasterName = (controllerContext, viewName, z) =>
            {
                var controllerName = controllerContext.RouteData.GetRequiredString("controller");
                var controllerType = controllerContext.Controller.GetType();
                var rootNamespace = (controllerType.FullName ?? string.Empty).Split('.')[0];
                var viewTypeName = string.Format("{0}.Views.{1}.{2}", rootNamespace, controllerName, viewName); // TODO settings???
                return controllerType.Assembly.GetType(viewTypeName, false, true);
            };
        }

        /// <summary>View engine created by this constructor will search views in namespaces and assembly of type in parameter.</summary>
        /// <param name="oneOfViewTypes">Type of view, view engine will search  all views in type's assembly and namespace.</param>
        public SharpDomViewEngine(Type oneOfViewTypes)
        {
            _findTypeByControllerContextViewNameAndMasterName = (controllerContext, viewName, z) =>
            {
                var controllerName = controllerContext.RouteData.GetRequiredString("controller");
                var rootNamespace = (oneOfViewTypes.Namespace ?? string.Empty).Substring(0, (oneOfViewTypes.Namespace ?? string.Empty).LastIndexOf('.') + 1);
                var viewTypeName = string.Format("{0}.Views.{1}.{2}", rootNamespace, controllerName, viewName); // TODO settings???
                return oneOfViewTypes.Assembly.GetType(viewTypeName, false, true);
            };
        }

        /// <summary>View engine created by this constructor will search views by function from parameter.</summary>
        /// <param name="findTypeByControllerContextViewNameAndMasterName">This function should search and return view types.</param>
        public SharpDomViewEngine(Func<ControllerContext, String, String, Type> findTypeByControllerContextViewNameAndMasterName)
        {
            _findTypeByControllerContextViewNameAndMasterName = findTypeByControllerContextViewNameAndMasterName;
        }

        /// <summary>Common find function for all views.</summary>
        /// <param name="controllerContext">Current controller context</param>
        /// <param name="viewName">Name of the view</param>
        /// <param name="masterName">Name of the master view</param>
        /// <returns></returns>
        protected ViewEngineResult FindCommon(ControllerContext controllerContext, string viewName, string masterName)
    	{
            var viewType = _findTypeByControllerContextViewNameAndMasterName(controllerContext, viewName, masterName);
    		if (viewType == null) return new ViewEngineResult(new string[0]);
    		var view = Activator.CreateInstance(viewType) as IView;
    		return new ViewEngineResult(view, this);
    	}

        /// <summary>Implementation of generic find function for partial views</summary>
        /// <param name="controllerContext">Current controller context</param>
        /// <param name="partialViewName">Partial view name</param>
        /// <param name="useCache">Cache option. Currently is not in use</param>
        /// <returns></returns>
        public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            return FindCommon(controllerContext, partialViewName, "");
        }

        /// <summary>Implementation of generic find function for page views</summary>
        /// <param name="controllerContext">Current controller context</param>
        /// <param name="viewName">View name</param>
        /// <param name="masterName">Master name</param>
        /// <param name="useCache">Should we use cache. Currently is not in use</param>
        /// <returns></returns>
        public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            return FindCommon(controllerContext, viewName, masterName);
        }

        /// <summary>
        /// Generic release view function. Is not implemented
        /// </summary>
        /// <param name="controllerContext"></param>
        /// <param name="view"></param>
        public void ReleaseView(ControllerContext controllerContext, IView view)
        {
            // TODO ???
        }
    }
}
